﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.Composition;
using System.Data;
using System.Linq;
using System.Text;
using Caliburn.Core.InversionOfControl;
using Caliburn.PresentationFramework;
using Caliburn.PresentationFramework.Filters;
using Caliburn.PresentationFramework.RoutedMessaging;
using Caliburn.ShellFramework.Questions;
using Caliburn.ShellFramework.Results;
using MTGenome.Framework;
using MTGenome.MTG;

namespace MTGenome.ViewModels
{
    [Singleton(typeof(DeckViewModel)), PartCreationPolicy(CreationPolicy.Shared)]
    public sealed class DeckViewModel : PropertyChangedBase
    {
        private readonly CardDetailViewModel _cardDetail;
        private readonly DialogViewModel _dialog;
        private readonly IDeckLoader _deckLoader;
        private bool _canSave = false;
        private string _fileName = null;
        private BindableCollection<CardQuantityViewModel> _cards = new BindableCollection<CardQuantityViewModel>();
        private BindableCollection<CardQuantityViewModel> _creatures = new BindableCollection<CardQuantityViewModel>();
        private BindableCollection<CardQuantityViewModel> _spells = new BindableCollection<CardQuantityViewModel>();
        private BindableCollection<CardQuantityViewModel> _lands = new BindableCollection<CardQuantityViewModel>();
        private BindableCollection<CardQuantityViewModel> _sideboard = new BindableCollection<CardQuantityViewModel>();

        public DeckViewModel(CardDetailViewModel cardDetail, DialogViewModel dialog, IDeckLoader deckLoader)
        {
            _cardDetail = cardDetail;
            _dialog = dialog;
            _deckLoader = deckLoader;
            _cards.CollectionChanged += (sender, e) =>
            {
                CanSave = true;
            };
        }

        public void Loaded()
        {
            //Checks for file association
            var activationArgs = AppDomain.CurrentDomain.SetupInformation.ActivationArguments;
            if (activationArgs != null)
            {
                string[] args = activationArgs.ActivationData;
                if (args != null && args.Length > 0 && args[0] != null && args[0].EndsWith(".MTGen") && System.IO.File.Exists(args[0]))
                {
                    Open(args[0]);
                }
            }
        }



        public CardQuantityViewModel SelectedCard { get; set; }

        public BindableCollection<CardQuantityViewModel> Cards
        {
            get { return _cards; }
        }

        public BindableCollection<CardQuantityViewModel> Sideboard
        {
            get { return _sideboard; }
        }


        public BindableCollection<CardQuantityViewModel> Creatures
        {
            get
            {
                var query = _cards.Where<CardQuantityViewModel>
                    (card =>
                        card.Card.Type.Contains("Creature ")
                    );

                _creatures.Clear();
                _creatures.AddRange(query);
                return _creatures;
            }
        }

        public BindableCollection<CardQuantityViewModel> Spells
        {
            get
            {
                var query = _cards.Where<CardQuantityViewModel>
                    (card =>
                        !card.Card.Type.Contains("Creature ") &
                        !card.Card.Type.Contains("Land ") 
                    );

                _spells.Clear();
                _spells.AddRange(query);
                return _spells;
            }
        }
        public BindableCollection<CardQuantityViewModel> Lands
        {
            get
            {
                var query = _cards.Where<CardQuantityViewModel>
                    (card =>
                        card.Card.Type.Contains("Land") 
                    );

                _lands.Clear();
                _lands.AddRange(query);
                return _lands;
            }
        }



        public IEnumerable<IResult> CardSelected()
        {
            yield return new AsyncResult(() =>
            {
                bool selectedCardIsInCreatures = _creatures.Contains(SelectedCard);
                bool selectedCardIsInSpells = _spells.Contains(SelectedCard);
                bool selectedCardIsInLands = _lands.Contains(SelectedCard);
                bool selectedCardIsInSideboard = _sideboard.Contains(SelectedCard);

                if (!selectedCardIsInCreatures)
                    foreach (CardQuantityViewModel card in _creatures)
                        card.IsSelected = false;

                if (!selectedCardIsInSpells)
                    foreach (CardQuantityViewModel card in _spells)
                        card.IsSelected = false;

                if (!selectedCardIsInLands)
                    foreach (CardQuantityViewModel card in _lands)
                        card.IsSelected = false;

                if (!selectedCardIsInSideboard)
                    foreach (CardQuantityViewModel card in _sideboard)
                        card.IsSelected = false;

            });
        }


        public int TotalCards
        {
            get { return _cards.Sum(c => c.Quantity); }
        }

        public CardDetailViewModel CardDetail
        {
            get { return _cardDetail; }
        }

        public bool CanAddCard
        {
            get { return _cardDetail.Card != null; }
        }
        
        [Dependencies("CardDetail.Card")]
        public void AddCard()
        {
            ICard card = _cardDetail.Card;
            CardQuantityViewModel current = _cards.FirstOrDefault(c => c.MultiverseID == card.MultiverseID);
            if (current != null)
            {
                current.Quantity++;
            }
            else
            {
                var cardQty = IoC.Get<CardQuantityViewModel>();
                cardQty.Card = card;
                _cards.Add(cardQty);
            }
        }

        [Dependencies("CardDetail.Card")]
        public void AddCardsToDeck(int amount)
        {
            ICard card = _cardDetail.Card;
            CardQuantityViewModel current = _cards.FirstOrDefault(c => c.MultiverseID == card.MultiverseID);
            if (current != null)
            {
                current.Quantity += amount;
            }
            else
            {
                var cardQty = IoC.Get<CardQuantityViewModel>();
                cardQty.Card = card;
                //cardQty.Expansion = card.Expansion;
                cardQty.Quantity = amount;
                _cards.Add(cardQty);
            }

            NotifyOfPropertyChange(() => Cards);
            NotifyOfPropertyChange(() => Creatures);
            NotifyOfPropertyChange(() => Spells);
            NotifyOfPropertyChange(() => Lands);
        }

        [Dependencies("CardDetail.Card")]
        public void AddCardsToSideboard(int amount)
        {
            ICard card = _cardDetail.Card;
            CardQuantityViewModel current = _sideboard.FirstOrDefault(c => c.MultiverseID == card.MultiverseID);
            if (current != null)
            {
                current.Quantity += amount;
            }
            else
            {
                var cardQty = IoC.Get<CardQuantityViewModel>();
                cardQty.Card = card;
                //cardQty.Expansion = card.Expansion;
                cardQty.Quantity = amount;
                _sideboard.Add(cardQty);
            }

            NotifyOfPropertyChange(() => Sideboard);
        }

        public bool CanRemoveCard
        {
            get { return _cardDetail.Card != null && _cards.Select(c => c.MultiverseID).Contains(_cardDetail.Card.MultiverseID); }
        }

        [Dependencies("CardDetail.Card", "Cards.Count")]
        public void RemoveCard()
        {
            ICard card = _cardDetail.Card;
            CardQuantityViewModel current = _cards.FirstOrDefault(c => c.MultiverseID == card.MultiverseID);
            if (current != null)
            {
                _cards.Remove(current);
            }
        }

        public bool CanSave
        {
            get { return _canSave; }
            set
            {
                if (_canSave != value)
                {
                    _canSave = value;
                    NotifyOfPropertyChange(() => CanSave);
                }
            }
        }

        public bool CanSaveAs
        {
            get { return _cards.Count > 0; }
        }

        public void Save()
        {
            Save(_fileName);
        }

        [Dependencies("Cards.Count")]
        public IEnumerable<IResult> SaveAs()
        {
            yield return Show.CommonDialog(_dialog.SaveFile);

            Save(_dialog.SaveFile.FileName);
        }

        private void Save(string path)
        {
            if (!string.IsNullOrEmpty(path))
            {
                var deck = IoC.Get<IDeck>();
                deck.Cards = _cards.Select(c => 
                {
                    var qty = IoC.Get<ICardQuantity>();
                    qty.MultiverseID = c.MultiverseID;
                    qty.Quantity = c.Quantity;
                    return qty;
                });
                _deckLoader.Save(deck, path);
                _fileName = path;
                CanSave = false;
            }
        }

        public IEnumerable<IResult> New()
        {
            bool yes = !CanSave;

            if (!yes)
            {
                yield return Show.MessageBox("Are you sure? You will lose your changes.", "New?", a => yes = a == Answer.Yes, Answer.Yes, Answer.No);
            }

            if (yes)
            {
                _cards.Clear();
                _cardDetail.Card = null;
                CanSave = false;
            }
        }

        public IEnumerable<IResult> Open()
        {
            bool yes = !CanSave;

            if (!yes)
            {
                yield return Show.MessageBox("Are you sure? You will lose your changes.", "Open?", a => yes = a == Answer.Yes, Answer.Yes, Answer.No);
            }

            if (yes)
            {
                yield return Show.CommonDialog(_dialog.OpenFile);

                Open(_dialog.OpenFile.FileName);
            }
        }

        private void Open(string path)
        {
            if (!string.IsNullOrEmpty(path))
            {
                IDeck deck = _deckLoader.Load(path);
                _cards.Clear();
                using (IDatabase database = IoC.Get<IDatabase>())
                {
                    foreach (var item in deck.Cards)
                    {
                        ICard card = database.Cards.FirstOrDefault(c => c.MultiverseID == item.MultiverseID);
                        if (card != null)
                        {
                            var cardQty = IoC.Get<CardQuantityViewModel>();
                            cardQty.Card = card;
                            cardQty.Quantity = item.Quantity;
                            _cards.Add(cardQty);
                        }
                    }
                }
                _fileName = path;
                CanSave = false;
            }
        }

        public IEnumerable<IResult> RemoveOneOfSelectedCardFromDeck() 
        {
            yield return new AsyncResult(() =>
            {
                if (SelectedCard.Quantity > 1)
                    SelectedCard.Quantity -= 1;
                else _cards.Remove(SelectedCard);
                NotifyOfPropertyChange(() => Cards);
                NotifyOfPropertyChange(() => Creatures);
                NotifyOfPropertyChange(() => Spells);
                NotifyOfPropertyChange(() => Lands);
            });
        }
        public IEnumerable<IResult> RemoveFourOfSelectedCardFromDeck() 
        {
            yield return new AsyncResult(() =>
            {
                if (SelectedCard.Quantity > 4)
                    SelectedCard.Quantity -= 4;
                else _cards.Remove(SelectedCard);
                NotifyOfPropertyChange(() => Cards);
                NotifyOfPropertyChange(() => Creatures);
                NotifyOfPropertyChange(() => Spells);
                NotifyOfPropertyChange(() => Lands);
            });
        }
        public IEnumerable<IResult> RemoveAllOfSelectedCardFromDeck() 
        {
            yield return new AsyncResult(() =>
            {
                _cards.Remove(SelectedCard);
                NotifyOfPropertyChange(() => Cards);
                NotifyOfPropertyChange(() => Creatures);
                NotifyOfPropertyChange(() => Spells);
                NotifyOfPropertyChange(() => Lands);
            });
        }
        public IEnumerable<IResult> RemoveOneOfSelectedCardFromSideboard() 
        {
            yield return new AsyncResult(() =>
            {
                if (SelectedCard.Quantity > 1)
                    SelectedCard.Quantity -= 1;
                else _sideboard.Remove(SelectedCard);
                NotifyOfPropertyChange(() => Sideboard);
            });
        }
        public IEnumerable<IResult> RemoveFourOfSelectedCardFromSideboard() 
        {
            yield return new AsyncResult(() =>
            {
                if (SelectedCard.Quantity > 1)
                    SelectedCard.Quantity -= 1;
                else _sideboard.Remove(SelectedCard);
                NotifyOfPropertyChange(() => Sideboard);
            });
        }
        public IEnumerable<IResult> RemoveAllOfSelectedCardFromSideboard() 
        {
            yield return new AsyncResult(() =>
            {
                _sideboard.Remove(SelectedCard);
                NotifyOfPropertyChange(() => Sideboard);
            });
        }
    }
}
